JNI/NDK入门指南之JNI数据类型,描述符详解

您所在的位置:网站首页 java 实例属性 JNI/NDK入门指南之JNI数据类型,描述符详解

JNI/NDK入门指南之JNI数据类型,描述符详解

2024-01-21 19:43| 来源: 网络整理| 查看: 265

       JNI/NDK入门指南之JNI数据类型,描述符详解

Android JNI/NDK入门指南目录

JNI/NDK入门指南之正确姿势了解JNI和NDK JNI/NDK入门指南之JavaVM和JNIEnv JNI/NDK入门指南之JNI数据类型,描述符详解 JNI/NDK入门指南之jobject和jclass JNI/NDK入门指南之javah和javap的使用和集成 JNI/NDK入门指南之Eclipse集成NDK开发环境并使用 JNI/NDK入门指南之JNI动/静态注册全分析 JNI/NDK入门指南之JNI字符串处理 JNI/NDK入门指南之JNI访问数组 JNI/NDK入门指南之C/C++通过JNI访问Java实例属性和类静态属性 JNI/NDK入门指南之C/C++通过JNI访问Java实例方法和类静态方法 JNI/NDK入门指南之JNI异常处理 JNI/NDK入门指南之JNI多线程回调Java方法 JNI/NDK入门指南之正确姿势了解,使用,管理,缓存JNI引用 JNI/NDK入门指南之调用Java构造方法和父类实例方法 JNI/NDK入门指南之C/C++结构体和Java对象转换方式一 JNI/NDK入门指南之C/C++结构体和Java对象转换方式二

引言

   通过前面的章节正确姿势了解Android中JNI/NDK,我想读者朋友们一定对JNI/NDK的基本概念印象深刻了吗,那么接下来就要开始我们的JNI编程学习了。学编程的东西,一般法则先学习它的最基础数据类型,同理JNI也是如此。既然JNI是用来C/C++和Java通信的,那么JNI为之定义了一系列基本数据类型和引用数据类型用来与Java交织呼应。那么在接下来的篇章里面我们会围绕JNI的数据类型和描述符为中心而开展。

注意:这里都是以32位CPU架构来说明!

基本数据类型

先从最简单的基本数据类型开始,看看JNI语法为其定义的相关法则。

Java Launage TypeJNI Native TypeC/C++ Launage TypeType Descriptionbooleanjbooleanunsigned charunsigned 8 bitsbytejbytesigned charsigned 8 bitscharjcharunsigned shortunsigned 16 bitsshortjshortsigned shortsigned 16 bitsintjintsigned intsigned 32 bitslongjlongsigned longsigned 64 bitsfloatjfloatfloat32 bitsdoublejdoubledouble64 bits

注意:这些数据类型是可以直接在JNI中直接使用的,不需要进行转换。

jbyte result=0xff; jint size; jbyte* timeBytes; 引用数据类型 Java Launage TypeJNI Native TypeType Descriptionjava.lang.Objectjobject可以表示任何Java的对象,或者没有JNI对应类型的Java对象(实例方法的强制参数)java.lang.StringjstringJava的String字符串类型的对象java.lang.ClassjclassJava的Class类型对象(静态方法的强制参数)Object[]jobjectArrayJava任何对象的数组boolean[]jbooleanArrayJava boolean型数组byte[]jbyteArrayJava byte型数组char[]jcharArrayJava char型数组short[]jshortArrayJava short型数组int[]jintArrayJava int型数组long[]jlongArrayJava long型数组float[]jfloatArrayJava float型数组double[]jdoubleArrayJava double型数组java.lang.ThrowablejthrowableJava的Throwable类型,表示异常的所有类型和子类voidvoidN/A

注意: (1) JNI中与Java字符串String相对应的jstring也是引用类型,这个切记。 (2) 数组也是引用数据类型,引用类型不能直接使用,要经过JNI函数转换才能使用。参见如下代码:

//获得一维数组的类引用,即jintArray类型 jclass intArrayClass = env->FindClass("[I"); int len = 10; //构造一个指向jintArray类一维数组的对象数组,该对象数组初始大小为len jobjectArray obejctIntArray = env->NewObjectArray(len,intArrayClass , NULL);

和Java中的继承关系类似,JNI引用类型也存在一个继承关系,当我们在进行JNI实际开发的时候,可以参照进行相对应的转换:

在这里插入图片描述

类描述符

假设这么一个场景,在JNI的Native方法中,我们要使用Java中的对象怎么办(包括你自定义的或者Android源码中已有的)?即在C/C++中怎么找到Java中的类,这就要使用到JNI开发中的类描述符了。JNI提供的函数中有个FindClass()就是用来查找Java类的,其参数必须放入一个类描述符字符串,类描述符一般是类的完整名称(包名+类名)。这么说是不是很抽象,下面我举几个栗子说明一下:

Java中String类

完整类名:   java.lang.String 对应类描述符: java/lang/String 即一个 Java 类对应的描述符,就是类的全名,其中 . 要换成 / ,最后 不要忘掉末尾的分号。 其实,在实践中,我发现可以直接用该类型的域描述符取代,也是可以成功的。 例如:  jclass intArrCls = env->FindClass(“java/lang/String”) 等同于: jclass intArrCls = env->FindClass(“Ljava/lang/String;”)

Android中Surface类

完整类名:   android.view.Surface 对应类描述符: android/view/Surface 即一个 Android 类对应的描述符,就是类的全名,其中 . 要换成 /

int err = RegisterMethodsOrDie(env, "android/view/Surface", gSurfaceMethods, NELEM(gSurfaceMethods)); jclass clazz = FindClassOrDie(env, "android/view/Surface"); 域描述符

看到这个名词是不是感觉有点懵逼,啥是域描述符。让我为你一一道来,域描述符是JNI中对Java数据类型的一种表示方法(就是对Java类中的变量,在JNI世界的定义),即在JVM虚拟机中,存储数据类型的名称时,是使用指定的描述符来存储,而不是我们习惯的 int,float 等。虽然有类描述符,但是类描述符里并没有说明基本类型和引用数据类型如何表示,所以在JNI中就引入了域描述符的概念。

1 基本类型域描述符

JNI在域描述符中已经定义好了基本类型的表示,其对照表格如下:

Java Launage TypeField DescriptionintIlongJbyteBshortScharCdoubleDbooleanZvoidV其它引用类型L+类全名+;数组[方法(参数)返回值 2 引用类型域描述符

一般引用类型则为 L + 该类型类描述符 + ; (注意,这儿的分号“;”只得是JNI的一部分,而不是我们汉语中的分段,下同)。这么说自我感觉也有那么点抽象,让我们举几个栗子说明一下:

2.1 String引用类型域描述符

Java类型:  java.lang.String JNI 域描述符:Ljava/lang/String; 扩展开来就是 即一个 Java 类对应的描述符,就是 L 加上类的全名,其中 . 要换成 / ,最后 不要忘掉末尾的分号。是不是有点按图索骥的感觉,那么让我么下面接着照葫芦画瓢再接再厉。

2.2 数组引用类型域描述符

对于数组,其通用规则为为 : [ + 其元素类型的域描述符,二维数组就是两个 [ ,以此类推,n维数组就有几个[ + 其元素类型的域描述符。 Java类型:   int[] JNI域描述符: [I Java类型:   float[] JNI域描述符: [F Java类型:   String[] JNI域描述符: [Ljava/lang/String; Java类型:   Object[ ] JNI域描述符: [[Ljava/lang/Object; 多维数组则是 n个[ +该元素域描述符 , N代表的是几维数组。例如: Java类型:   int[][] JNI域描述符: [[I Java类型:   float[][] JNI域描述符: [[F

get_field(env, javaBean_clazz, "boolValue", "Z", &javaBean_t.boolValue); get_field(env, javaBean_clazz, "charValue", "C", &javaBean_t.charValue); get_field(env, javaBean_clazz, "doubleValue", "D", &javaBean_t.doubleValue); get_field(env, javaBean_clazz, "intValue", "I", &javaBean_t.intVaule); get_field(env, javaBean_clazz, "array", "[B", &javaBean_t.byteArray); get_field(env, javaBean_clazz, "mDoubleDimenArray", "[[I", &javaBean_t.double_dimen_array); get_field(env, javaBean_clazz, "stringValue", "Ljava/lang/String;", &javaBean_t.stringValue); get_field(env, javaBean_clazz, "mInnerClass", "Lcom/xxx/object2struct/JavaBean$InnerClass;", &javaBean_t.inner_message); 方法描述符

Java世界的类,变量都在JNI世界找到了对应的规则了,各位读者亲朋友们,有没有发现Java类中的方法是不是还没有一个对应的法则呢,本章节就要来说JNI中对应Java方法的方法描述符了。方法描述符定义了方法的返回值和参数的表示形式,将参数类型的域描述符按声明顺序放入一对括号中(如果没有参数则不需要括号),括号后跟返回值类型的域描述符即形成方法描述符。我想各位对方法描述符的定义有了一定理解了,那么让我们来举几个栗子说明一下:

Java MethodMethod DescriptionString fun()()Ljava/lang/String;int fun(int i, Object object)(ILjava/lang/Object;)Ivoid fun(byte[ ] bytes)([B)Vint fun(byte data1, byte data2)(BB)Ivoid fun()()V

注意,void的处理比较特殊,如果返回值为void,那么方法描述符中必须使用V表示,当void作为参数的时候,忽略。

static JNINativeMethod gMethods[] = { {"getJavaBeanFromNative", "()Lcom/xxx/object2struct/JavaBean;",(void*)Java_com_xxx_object2struct_JniTransfer_getJavaBeanFromNative }, {"transferJavaBeanToNative", "(Lcom/xxx/object2struct/JavaBean;)V",(void*)Java_com_xxx_object2struct_JniTransfer_transferJavaBeanToNative }, };

补充点:当我们使用JDK内置工具javah生成JNI的头文件的时候(当然这个工具得配置一下才能使用),我们会发现javah头文件注释中已经生成了本地方法的方法描述符,但是它偏不叫方法描述符而是叫做Signature,所以我们也可以把方法描述符直译为签名,形如:

#include /* Header for class com_xxx_xxxndk_XxxNative */ #ifndef _Included_com_xxx_xxxndk_XxxNative #define _Included_com_xxx_xxxndk_XxxNative #ifdef __cplusplus extern "C" { #endif /* * Class: com_xxx_xxxndk_XxxNative * Method: getCurrentTime * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_xxx_xxxndk_XxxNative_getCurrentTime (JNIEnv *, jobject); /* * Class: com_xxx_apifunctest_test_XxxNative * Method: Prn_Vline * Signature: ()V */ JNIEXPORT void JNICALL Java_com_xxx_apifunctest_test_XxxNative_Prn_1Vline (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif 写在最后

   通过本章的细述,我想各位读者朋友们一定对JNI的数据类型,以及描述符有了比较详细的了解了。在本篇章的最后,我们有说到了javah工具,这个我们会在后面的章节里面详细介绍的。不要着急。青山不改绿水长流,各位江湖见!



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3